Skip to content

feat(FR-2691): relocate /data header panels — Dashboard + host-capacity cell#6941

Merged
graphite-app[bot] merged 1 commit into
mainfrom
04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell
Apr 30, 2026
Merged

feat(FR-2691): relocate /data header panels — Dashboard + host-capacity cell#6941
graphite-app[bot] merged 1 commit into
mainfrom
04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell

Conversation

@ironAiken2
Copy link
Copy Markdown
Contributor

@ironAiken2 ironAiken2 commented Apr 23, 2026

resolves #6937 (FR-2691)

Summary

Clears the three header panels that used to sit above the folder table on /data, redistributes their responsibilities, and reshapes the "Location" column into a "Host" column that surfaces per-volume capacity info without requiring an extra click on every row.

Changes on /data (VFolderNodeListPage.tsx)

  • Removed the top Row that rendered the Create Folder action card, StorageStatusPanelCard, and QuotaPerStorageVolumePanelCard. The Create Folder affordance is already present as the primary button inside the folder table card header, so no replacement action card is needed.
  • Promoted the folder table card to the top of the page.
  • Cleaned up now-unused imports / variables (ActionItemContent, BAINewFolderIcon, BAIAlertIconWithTooltip, Grid.useBreakpoint, useWebUINavigate, ErrorBoundary, per-row Suspense, CARD_MIN_HEIGHT).

Changes in the folder table (VFolderNodesV2.tsx)

  • Column title: data.folders.Location (위치) → data.Host (호스트).
  • Column header affordance: a BAIAlertIconWithTooltip sits next to the "Host" label. Clicking it opens the QuotaPerStorageVolumePanelCard in a Modal, pre-selected on a quota-supporting host. The icon is hidden entirely when no volume reports "quota" in capabilities, so the modal entry point disappears when the feature is unusable — we don't open a dialog with no useful content.
  • Column cells: new VFolderHostCell renders a StorageUsageBadge (sourced from vfolder.list_hosts(), cached under the shared ['vhostInfo'] tan-query key that StorageSelect already uses) plus the host name. No per-cell click behavior — the modal is only reachable via the column-header affordance.
  • Badge gating matches StorageSelect's own precedent: the badge renders whenever the backend attaches a usage object (even {}). StorageUsageBadge resolves a percentage-less usage to a neutral (uncolored) marker. The accompanying tooltip reads Host Status: <Adequate | Caution | Insufficient | Unknown>; the Unknown label is a newly added key that covers the "backend reports no percentage" case.
  • Switched the cell from useSuspenseTanQuery to useTanQuery. A per-cell Suspense boundary whose fallback rendered the bare host text (visually indistinguishable from the "loaded but no usage data" branch) caused rows to stick in the fallback even after vhostInfo resolved.

Changes to QuotaPerStorageVolumePanelCard.tsx

  • Dropped the outer BAICard wrapper and the internal title. The consumer is now a Modal that supplies its own title and chrome, and a nested card here produced a duplicated header on top of the modal frame.
  • Moved the ? tooltip icon (QuestionCircleOutlined with data.HostDetails) into the Modal title so all header affordances live in one place.
  • StorageSelect moved out of the former card's extra slot (right-aligned, borderless) and into the modal body as the first element, left-aligned with a sensible minWidth.
  • Added defaultVolumeInfo?: VolumeInfo prop. When set, the card seeds selectedVolumeInfo with that value and disables the built-in autoSelectType="usage" fallback; users can still switch volumes through the inline StorageSelect. This is how the header icon pre-selects a quota-supporting host.
  • Props type simplified: BAICardProps → a dedicated local interface (card-specific passthrough props no longer make sense).

Changes on the Dashboard (DashboardPage.tsx, StorageStatusPanelCard.tsx)

  • Added a new folderStatus board item between myResourceWithinResourceGroup and totalResourceWithinResourceGroup, wrapped in BAIBoardItemErrorBoundary + Suspense. Invitation badge click routes to /data?invitation=true through useWebUINavigate.
  • Refactored StorageStatusPanelCard to follow the Dashboard board-item pattern used by MyResource / MyResourceWithinResourceGroup:
    • Root is a BAIFlex direction="column" align="stretch" with paddingInline: token.paddingXL and paddingBottom: token.padding.
    • Title uses the shared BAIBoardItemTitle, which reserves space for the board's drag handle. Wrapping in a BAICard caused the title to overlap the handle on the left edge — that's fixed.
    • Props type: BAICardPropsBAIFlexProps.

V2 migration notes (TODOs left in StorageStatusPanelCard.tsx)

The status counts still run off the legacy REST call baiClient.vfolder.list() and the V1 user_resource_policy / project_resource_policy GraphQL root fields. TODOs in the file call out the V2 rewrite with explicit scoping rules:

  • ProjectFolders: when ported to projectVfolders(projectId: …), it must be scoped to the project currently selected in the global header project selector (currentProject.id), not aggregated across every project the user can see.
  • InvitedFolders: migration deferred. The V2 VFolderFilter does not yet expose an "invited only / received share" predicate, so we cannot reproduce the current !is_owner && ownership_type === 'user' filter with a single server-side count. Stays on legacy REST until the backend adds the filter field; revisit in a follow-up issue.

Internationalization

Added data.usage.Unknown to all 21 locales under resources/i18n/, placed alphabetically between StatusOfSelectedHost and Used in the data.usage object. The key powers the tooltip fallback when a host has usage: {} (object present, percentage missing). packages/backend.ai-ui/src/locale/*.json is intentionally untouched — that package does not consume the key.

Testing

  • bash scripts/verify.sh — Relay, Lint, Format, TypeScript all pass on this branch and on every descendant branch in the stack (FR-2573, FR-2619, FR-2685, FR-2688).
  • Manually verified against a manager response where every volume reports usage: {} (no percentage): per-row neutral badges render with Host Status: Unknown tooltip; header ? icon appears because icn02:flash01 / seoul-h100:flash0* advertise "quota" in capabilities; clicking it opens the modal pre-selected on the first quota-capable host.

Checklist: (if applicable)

  • Documentation
  • Minimum required manager version
  • Specific setting for review (eg., KB link, endpoint or how to setup)
  • Minimum requirements to check during review
  • Test case(s) to demonstrate the difference of before/after

Copy link
Copy Markdown
Contributor Author

ironAiken2 commented Apr 23, 2026


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • flow:merge-queue - adds this PR to the back of the merge queue
  • flow:hotfix - for urgent changes, fast-track this PR to the front of the merge queue

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has required the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 23, 2026

Coverage report for ./react

St.
Category Percentage Covered / Total
🔴 Statements
8.87% (-0.02% 🔻)
1859/20957
🔴 Branches
8.05% (-0.01% 🔻)
1187/14750
🔴 Functions
5.22% (+0% 🔼)
297/5686
🔴 Lines
8.61% (-0.02% 🔻)
1750/20332
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🔴
... / QuotaPerStorageVolumeDashboardItem.tsx
0% 0% 0% 0%

Test suite run success

865 tests passing in 40 suites.

Report generated by 🧪jest coverage report action from 687147d

@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch from b068ff5 to fbabca7 Compare April 23, 2026 07:59
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from 2a1e7e6 to 8d4bf6b Compare April 23, 2026 07:59
@ironAiken2 ironAiken2 marked this pull request as ready for review April 23, 2026 08:33
Copilot AI review requested due to automatic review settings April 23, 2026 08:33
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch from fbabca7 to aa129c7 Compare April 23, 2026 08:35
@github-actions github-actions Bot added area:ux UI / UX issue. area:i18n Localization size:XL 500~ LoC and removed size:L 100~500 LoC labels Apr 23, 2026
@ironAiken2 ironAiken2 requested review from agatha197, Copilot, nowgnuesLee and yomybaby and removed request for Copilot April 23, 2026 08:38
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from 8d4bf6b to b3429c8 Compare April 24, 2026 04:02
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch from aa129c7 to 5ac60d3 Compare April 24, 2026 04:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Relocates the /data page header panels by moving folder-status information to the Dashboard, and enhances the vfolder list by surfacing per-host capacity/usage context directly in the “Host” column (with a modal entry point for per-volume quota details).

Changes:

  • Removed the /data page’s top header panel row and promoted the folder table card to the top.
  • Added a new Dashboard board item rendering StorageStatusPanelCard, including navigation to /data?invitation=true.
  • Reworked the vfolder table “Host” column to show a per-host usage badge and added a header tooltip icon that opens QuotaPerStorageVolumePanelCard in a modal (plus i18n key data.usage.Unknown across locales).

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
react/src/pages/VFolderNodeListPage.tsx Removes the /data header panels row and cleans up related imports/usage.
react/src/pages/DashboardPage.tsx Adds the folder-status board item and wires invitation navigation to /data.
react/src/components/VFolderNodesV2.tsx Replaces “Location” with “Host” column, adds host usage badge cell + quota modal trigger.
react/src/components/QuotaPerStorageVolumePanelCard.tsx Refactors quota panel to be modal-body-friendly; adds defaultVolumeInfo for preselection.
react/src/components/StorageStatusPanelCard.tsx Refactors layout to a Dashboard board-item body using BAIFlex + BAIBoardItemTitle.
resources/i18n/en.json Adds data.usage.Unknown translation key.
resources/i18n/de.json Adds data.usage.Unknown translation key.
resources/i18n/el.json Adds data.usage.Unknown translation key.
resources/i18n/es.json Adds data.usage.Unknown translation key.
resources/i18n/fi.json Adds data.usage.Unknown translation key.
resources/i18n/fr.json Adds data.usage.Unknown translation key.
resources/i18n/id.json Adds data.usage.Unknown translation key.
resources/i18n/it.json Adds data.usage.Unknown translation key.
resources/i18n/ja.json Adds data.usage.Unknown translation key.
resources/i18n/ko.json Adds data.usage.Unknown translation key.
resources/i18n/mn.json Adds data.usage.Unknown translation key.
resources/i18n/ms.json Adds data.usage.Unknown translation key.
resources/i18n/pl.json Adds data.usage.Unknown translation key.
resources/i18n/pt-BR.json Adds data.usage.Unknown translation key.
resources/i18n/pt.json Adds data.usage.Unknown translation key.
resources/i18n/ru.json Adds data.usage.Unknown translation key.
resources/i18n/th.json Adds data.usage.Unknown translation key.
resources/i18n/tr.json Adds data.usage.Unknown translation key.
resources/i18n/vi.json Adds data.usage.Unknown translation key.
resources/i18n/zh-CN.json Adds data.usage.Unknown translation key.
resources/i18n/zh-TW.json Adds data.usage.Unknown translation key.

Comment thread react/src/components/VFolderNodesV2.tsx Outdated
Comment thread react/src/components/QuotaPerStorageVolumePanelCard.tsx Outdated
Comment thread react/src/components/VFolderNodesV2.tsx
Comment thread react/src/components/VFolderNodesV2.tsx
Comment thread react/src/components/VFolderNodesV2.tsx Outdated
@ironAiken2 ironAiken2 changed the base branch from graphite-base/6941 to 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api April 24, 2026 06:02
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch from 824d4b3 to 058f802 Compare April 24, 2026 06:29
@ironAiken2
Copy link
Copy Markdown
Contributor Author

@agatha197 Thanks for testing! Previously the host-capacity badge was only rendered when vfolder.list_hosts() returned a usage object (which is why it didn't show on dogbowl). This is now corrected so the Host column still renders the host name + a neutral badge even when host info can't be loaded. Please re-verify against dogbowl when you get a chance.

@ironAiken2 ironAiken2 requested a review from agatha197 April 24, 2026 06:30
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch from 058f802 to 9c45759 Compare April 27, 2026 02:42
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch 2 times, most recently from 42e2427 to 2ab0d52 Compare April 27, 2026 04:19
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch 3 times, most recently from c84cd7c to 91a0feb Compare April 27, 2026 06:57
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch 2 times, most recently from 6f4f7f0 to 1d95414 Compare April 27, 2026 08:55
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch 2 times, most recently from 025ecbb to dabf732 Compare April 27, 2026 10:00
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch 2 times, most recently from ac4de81 to 7db3eb6 Compare April 28, 2026 02:03
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch from dabf732 to 7a91a43 Compare April 28, 2026 02:03
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from 7db3eb6 to 03cf13c Compare April 28, 2026 03:21
@ironAiken2 ironAiken2 force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch 2 times, most recently from 2af4049 to f1aff6a Compare April 29, 2026 01:07
@ironAiken2 ironAiken2 force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from 03cf13c to 99b663c Compare April 29, 2026 01:07
@graphite-app
Copy link
Copy Markdown

graphite-app Bot commented Apr 30, 2026

Merge activity

…ty cell (#6941)

resolves #6937 (FR-2691)

## Summary

Clears the three header panels that used to sit above the folder table on `/data`, redistributes their responsibilities, and reshapes the "Location" column into a "Host" column that surfaces per-volume capacity info without requiring an extra click on every row.

## Changes on `/data` (`VFolderNodeListPage.tsx`)

- Removed the top `Row` that rendered the Create Folder action card, `StorageStatusPanelCard`, and `QuotaPerStorageVolumePanelCard`. The Create Folder affordance is already present as the primary button inside the folder table card header, so no replacement action card is needed.
- Promoted the folder table card to the top of the page.
- Cleaned up now-unused imports / variables (`ActionItemContent`, `BAINewFolderIcon`, `BAIAlertIconWithTooltip`, `Grid.useBreakpoint`, `useWebUINavigate`, `ErrorBoundary`, per-row `Suspense`, `CARD_MIN_HEIGHT`).

## Changes in the folder table (`VFolderNodesV2.tsx`)

- Column `title`: `data.folders.Location` (위치) → `data.Host` (호스트).
- Column header affordance: a `BAIAlertIconWithTooltip` sits next to the "Host" label. Clicking it opens the `QuotaPerStorageVolumePanelCard` in a Modal, pre-selected on a quota-supporting host. The icon is hidden entirely when no volume reports `"quota"` in `capabilities`, so the modal entry point disappears when the feature is unusable — we don't open a dialog with no useful content.
- Column cells: new `VFolderHostCell` renders a `StorageUsageBadge` (sourced from `vfolder.list_hosts()`, cached under the shared `['vhostInfo']` tan-query key that `StorageSelect` already uses) plus the host name. **No** per-cell click behavior — the modal is only reachable via the column-header affordance.
- Badge gating matches `StorageSelect`'s own precedent: the badge renders whenever the backend attaches a `usage` object (even `{}`). `StorageUsageBadge` resolves a `percentage`-less `usage` to a neutral (uncolored) marker. The accompanying tooltip reads `Host Status: <Adequate | Caution | Insufficient | Unknown>`; the `Unknown` label is a newly added key that covers the "backend reports no percentage" case.
- Switched the cell from `useSuspenseTanQuery` to `useTanQuery`. A per-cell Suspense boundary whose fallback rendered the bare host text (visually indistinguishable from the "loaded but no usage data" branch) caused rows to stick in the fallback even after `vhostInfo` resolved.

## Changes to `QuotaPerStorageVolumePanelCard.tsx`

- Dropped the outer `BAICard` wrapper and the internal title. The consumer is now a `Modal` that supplies its own title and chrome, and a nested card here produced a duplicated header on top of the modal frame.
- Moved the `?` tooltip icon (`QuestionCircleOutlined` with `data.HostDetails`) into the Modal title so all header affordances live in one place.
- `StorageSelect` moved out of the former card's `extra` slot (right-aligned, borderless) and into the modal body as the first element, left-aligned with a sensible `minWidth`.
- Added `defaultVolumeInfo?: VolumeInfo` prop. When set, the card seeds `selectedVolumeInfo` with that value and disables the built-in `autoSelectType="usage"` fallback; users can still switch volumes through the inline `StorageSelect`. This is how the header icon pre-selects a quota-supporting host.
- Props type simplified: `BAICardProps` → a dedicated local interface (card-specific passthrough props no longer make sense).

## Changes on the Dashboard (`DashboardPage.tsx`, `StorageStatusPanelCard.tsx`)

- Added a new `folderStatus` board item between `myResourceWithinResourceGroup` and `totalResourceWithinResourceGroup`, wrapped in `BAIBoardItemErrorBoundary` + `Suspense`. Invitation badge click routes to `/data?invitation=true` through `useWebUINavigate`.
- Refactored `StorageStatusPanelCard` to follow the Dashboard board-item pattern used by `MyResource` / `MyResourceWithinResourceGroup`:
  - Root is a `BAIFlex direction="column" align="stretch"` with `paddingInline: token.paddingXL` and `paddingBottom: token.padding`.
  - Title uses the shared `BAIBoardItemTitle`, which reserves space for the board's drag handle. Wrapping in a `BAICard` caused the title to overlap the handle on the left edge — that's fixed.
  - Props type: `BAICardProps` → `BAIFlexProps`.

## V2 migration notes (TODOs left in `StorageStatusPanelCard.tsx`)

The status counts still run off the legacy REST call `baiClient.vfolder.list()` and the V1 `user_resource_policy` / `project_resource_policy` GraphQL root fields. TODOs in the file call out the V2 rewrite with explicit scoping rules:

- **ProjectFolders**: when ported to `projectVfolders(projectId: …)`, it must be scoped to the project currently selected in the global header project selector (`currentProject.id`), not aggregated across every project the user can see.
- **InvitedFolders**: migration deferred. The V2 `VFolderFilter` does not yet expose an "invited only / received share" predicate, so we cannot reproduce the current `!is_owner && ownership_type === 'user'` filter with a single server-side count. Stays on legacy REST until the backend adds the filter field; revisit in a follow-up issue.

## Internationalization

Added `data.usage.Unknown` to all 21 locales under `resources/i18n/`, placed alphabetically between `StatusOfSelectedHost` and `Used` in the `data.usage` object. The key powers the tooltip fallback when a host has `usage: {}` (object present, `percentage` missing). `packages/backend.ai-ui/src/locale/*.json` is intentionally untouched — that package does not consume the key.

## Testing

- `bash scripts/verify.sh` — Relay, Lint, Format, TypeScript all pass on this branch and on every descendant branch in the stack (FR-2573, FR-2619, FR-2685, FR-2688).
- Manually verified against a manager response where every volume reports `usage: {}` (no `percentage`): per-row neutral badges render with `Host Status: Unknown` tooltip; header `?` icon appears because `icn02:flash01` / `seoul-h100:flash0*` advertise `"quota"` in capabilities; clicking it opens the modal pre-selected on the first quota-capable host.

**Checklist:** (if applicable)

- [ ] Documentation
- [ ] Minimum required manager version
- [ ] Specific setting for review (eg., KB link, endpoint or how to setup)
- [ ] Minimum requirements to check during review
- [ ] Test case(s) to demonstrate the difference of before/after
@graphite-app graphite-app Bot force-pushed the 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api branch from 99b663c to 7c822bb Compare April 30, 2026 03:08
@graphite-app graphite-app Bot force-pushed the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch from f1aff6a to 687147d Compare April 30, 2026 03:08
Base automatically changed from 04-21-feat_fr-2613_migrate_vfolder_trash_lifecycle_mutations_to_v2_graphql_api to main April 30, 2026 03:12
@graphite-app graphite-app Bot merged commit 687147d into main Apr 30, 2026
8 checks passed
@graphite-app graphite-app Bot deleted the 04-23-feat_fr-2691_relocate__data_header_panels_dashboard_host-capacity_cell branch April 30, 2026 03:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:i18n Localization area:ux UI / UX issue. size:XL 500~ LoC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Move folder-status panel from /data to Dashboard and surface per-volume capacity in the folder table

3 participants